#include <string.h>
#include "utils/circle_buffer.h"
#include "utils/utils.h"

c_buffer_t *circle_buffer_init(c_buffer_t *cbuff, u8 *buffer, int32_t max_len){
	memset(cbuff, 0, sizeof(c_buffer_t));
	cbuff->buffer = buffer;
	cbuff->size = max_len;
	return cbuff;
}

void circle_reset(c_buffer_t *cbuff){
	cbuff->r_pos = cbuff->w_pos = 0;
}

int32_t circle_put_bytes(c_buffer_t *cbuff, u8 *data, int32_t len){
	int32_t size = 0;
	while(size < len){
		int32_t curr_pos = (cbuff->w_pos + 1) % cbuff->size;
		if (curr_pos == cbuff->r_pos) {
			return size;
		}
		cbuff->buffer[cbuff->w_pos] = data[size++];
		cbuff->w_pos = curr_pos;
	}
	return size;
}


int32_t circle_put_byte(c_buffer_t *cbuff, u8 data){
	return circle_put_bytes(cbuff, &data, 1);
}


int32_t circle_get_bytes(c_buffer_t *cbuff, u8 *data, int32_t len){
	int32_t size = 0;
	while(size < len){
		if (cbuff->r_pos == cbuff->w_pos) {
			return size;
		}
		data[size++] = cbuff->buffer[cbuff->r_pos];
		cbuff->r_pos = (cbuff->r_pos + 1) % cbuff->size;
	}
	return size;
}

int32_t circle_get_byte(c_buffer_t *cbuff, u8 *data){
	return circle_get_bytes(cbuff, data, 1);
}

/* used for dma read */
u32 circle_get_read_size(c_buffer_t *cbuff) {
	if (cbuff->w_pos >= cbuff->r_pos) {
		return (cbuff->w_pos - cbuff->r_pos);
	}else {//if w_pos is after r_pos, we only return the size which is r_pos to the buffer end
		return (cbuff->size - cbuff->r_pos);
	}
}

#ifndef USE_MEX_CMD //simulink not used, this will drop the build warnning
/* used for dma read */
u32 circle_get_read_head(c_buffer_t *cbuff) {
	return ((u32)cbuff->buffer + cbuff->r_pos);
}
#endif

void circle_skip_read_size(c_buffer_t *cbuff, int32_t size) {
	cbuff->r_pos = (cbuff->r_pos + size) % cbuff->size;
}
